package com.example.demo.filter;

import com.example.demo.error.ApiResponse;
import com.example.demo.code.CustomStatusCode;
import com.example.demo.service.JwtService;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;

@Component
@WebFilter(urlPatterns = "/*")
public class JwtRequestFilter implements Filter {

    private static final Logger logger = Logger.getLogger(JwtRequestFilter.class.getName());

    @Autowired
    private JwtService jwtService;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 1 获取请求路径
        String url = request.getRequestURI();
        logger.info("请求URL: " + url);

        // 2 判断请求路径是否包含/auth/login
        if (url.contains("/auth/login")) {
            logger.info("检测到登录请求，允许访问。");
            // 如果包含，则放行
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        // 3 获取请求头中的token
        String authorizationHeader = request.getHeader("Authorization");
        logger.info("授权头: " + authorizationHeader);
        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            logger.warning("无效的授权头格式。");
            ApiResponse noLogin = ApiResponse.builder()
                    .code(CustomStatusCode.UNAUTHORIZED.getCode())
                    .msg(CustomStatusCode.UNAUTHORIZED.getDescription())
                    .data(null)
                    .dataSize(0)
                    .build();
            writeResponse(response, noLogin);
            return;
        }

        // 4 提取token
        String token = authorizationHeader.substring(7); // 去掉 "Bearer " 前缀
        logger.info("提取的Token: " + token);

        // 5 校验token
        try {
            String username = jwtService.extractUsername(token);
            logger.info("从Token中提取的用户名: " + username);
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            if (jwtService.validateToken(token, userDetails)) {
                logger.info("Token验证成功，用户: " + username);
                // 6 设置 SecurityContextHolder
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                logger.info("已将身份验证信息设置到SecurityContextHolder，用户: " + username);
            } else {
                logger.warning("Token验证失败，用户: " + username);
                throw new Exception("无效的JWT令牌");
            }
        } catch (Exception e) {
            logger.severe("Token验证过程中发生异常: " + e.getMessage());
            ApiResponse noLogin = ApiResponse.builder()
                    .code(CustomStatusCode.INVALID_CREDENTIALS.getCode())
                    .msg(CustomStatusCode.INVALID_CREDENTIALS.getDescription())
                    .data(null)
                    .dataSize(0)
                    .build();
            writeResponse(response, noLogin);
            return;
        }

        // 7 放行
        logger.info("请求允许继续。");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    private void writeResponse(HttpServletResponse response, ApiResponse apiResponse) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(apiResponse);
        response.getWriter().write(json);
    }
}